package com.startx.http.system.tool;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;

/**
 * 属性拷贝
 * @author minghu.zhang
 */
@SuppressWarnings({ "rawtypes", "unchecked" })
public class CopyField {
	
	private static final Logger Log4j = Logger.getLogger(CopyField.class);
	/**
	 * 属性拷贝 obj2map
	 * @param values  源Map
	 * @param target  目标对象
	 */
	public static Object copyMap2Obj(Map<String,Object> values,Object target) {
		try {
			for(String key:values.keySet()) {
				if(key == null) continue;
				Field df = null;
				try {
					df = target.getClass().getDeclaredField(key);
				} catch (NoSuchFieldException e) {
					continue;
				}
				Object value = values.get(key);
				
				if(value == null) {
					continue;
				}
				
				Type fieldType = df.getType();
				
				if(fieldType.equals(byte.class)) {
					fieldType = Byte.class;
				} else if(fieldType.equals(short.class)) {
					fieldType = Short.class;
				} else if(fieldType.equals(int.class)) {
					fieldType = Integer.class;
				} else if(fieldType.equals(long.class)) {
					fieldType = Long.class;
				} else if(fieldType.equals(float.class)) {
					fieldType = Float.class;
				} else if(fieldType.equals(double.class)) {
					fieldType = Double.class;
				} else if(fieldType.equals(boolean.class)) {
					fieldType = Boolean.class;
				} else if(fieldType.equals(Date.class)) {
					fieldType = Date.class;
				}
				
//				if(!fieldType.equals(value.getClass())) {
//					continue;
//				}
				
				df.setAccessible(true);
				
				if(value.getClass().equals(BigDecimal.class)) {
					
					if(fieldType.equals(Integer.class) || fieldType.equals(int.class)) {
						df.set(target,  ((BigDecimal)value).intValue());
					} else if(fieldType.equals(Long.class) || fieldType.equals(long.class)) {
						df.set(target,  ((BigDecimal)value).longValue());
					}
					
				} else {
				
					df.set(target,value);
				
				}
			}
		} catch (SecurityException | IllegalArgumentException
				| IllegalAccessException e) {
			Log4j.fatal(e.getMessage(), e);
		}
		
		return target;
	}
	
	/**
	 * 属性拷贝 obj2map
	 * @param target  源对象
	 * @param values  目标Map
	 */
	public static Map<String,Object> copyObj2Map(Object source,Map<String,Object> values) {
		try {
			for(Field f:source.getClass().getDeclaredFields()) {
				f.setAccessible(true);
				String key = f.getName();
				Object value = f.get(source);
				if(value == null) {
					continue;
				}
				values.put(key, value);
			}
		} catch (SecurityException | IllegalArgumentException
				| IllegalAccessException e) {
			Log4j.fatal(e.getMessage(), e);
		}
		
		return values;
	}

	/**
	 * 属性拷贝 obj2obj
	 * @param source  源对象
	 * @param target  目标对象
	 */
	public static Object copyObj2Obj(Object source, Object target) {

		String fileName, str, getName, setName;
		List fields = new ArrayList();
		Method getMethod = null;
		Method setMethod = null;
		try {
			Class c1 = source.getClass();
			Class c2 = target.getClass();

			Field[] fs1 = c1.getDeclaredFields();
			Field[] fs2 = c2.getDeclaredFields();
			// 两个类属性比较剔除不相同的属性，只留下相同的属性
			for (int i = 0; i < fs2.length; i++) {
				for (int j = 0; j < fs1.length; j++) {
					if (fs1[j].getName().equals(fs2[i].getName())) {
						fields.add(fs1[j]);
						break;
					}
				}
			}
			if (null != fields && fields.size() > 0) {
				for (int i = 0; i < fields.size(); i++) {
					// 获取属性名称
					Field f = (Field) fields.get(i);
					boolean stati = Modifier.isStatic(f.getModifiers());
					if(stati) continue;
					fileName = f.getName();
					// 属性名第一个字母大写
					str = fileName.substring(0, 1).toUpperCase();
					// 拼凑getXXX和setXXX方法名
					getName = "get" + str + fileName.substring(1);
					setName = "set" + str + fileName.substring(1);
					// 获取get、set方法
					getMethod = c1.getMethod(getName, new Class[] {});
					setMethod = c2.getMethod(setName,
							new Class[] { f.getType() });

					// 获取属性值
					Object value = getMethod.invoke(source, new Object[] {});
					// 将属性值放入另一个对象中对应的属性
					if (value != null) {
						setMethod.invoke(target, new Object[] { value });
					}
				}
			}
		} catch (SecurityException | NoSuchMethodException | IllegalAccessException | IllegalArgumentException
				| InvocationTargetException e) {
			Log4j.fatal(e.getMessage(), e);
		}
		
		return target;
	}
}
